﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.IO.Packaging;

namespace OPCDiffCore.Binaries
{
    class BinaryAnalyzer : PartAnalyzer
    {
        internal override PartDiff Analyze(PackagePart originalPart, PackagePart diffPart, AnalyzeLevel level)
        {
            // Check parameters
            if (originalPart == null)
                return new PartDiff(diffPart.Uri, diffPart.ContentType, DiffType.Added);

            if (diffPart == null)
                return new PartDiff(originalPart.Uri, originalPart.ContentType, DiffType.Removed);

            if (originalPart == null && diffPart == null)
                throw new ArgumentNullException("'originalPart' and 'diffPart' are null !");

            if (originalPart == diffPart)
                return new PartDiff(originalPart.Uri, originalPart.ContentType, DiffType.Unchanged);


            const short buffLimit = 0x1000;
            char[] bOrig = new char[buffLimit], bDiff = new char[buffLimit];

            using (Stream sOrig = originalPart.GetStream())
            {
                using (Stream sDiff = diffPart.GetStream())
                {
                    StreamReader srOrig = new StreamReader(sOrig);
                    StreamReader srDiff = new StreamReader(sDiff);
                    try
                    {
                        int iBeg = 0, c;
                        while ((c = srOrig.ReadBlock(bOrig, iBeg, buffLimit)) > 1 &&
                            (c == srDiff.ReadBlock(bDiff, iBeg, buffLimit)))
                        {
                            for (int i = 0; i < buffLimit; ++i)
                            {
                                if (bOrig[i] != bDiff[i])
                                    return new PartDiff(originalPart.Uri, originalPart.ContentType, DiffType.Modified);
                            }
                            iBeg += buffLimit;
                        }
                    }
                    catch (Exception)
                    {
                        return null;
                    }
                }
            }
            return new PartDiff(originalPart.Uri, originalPart.ContentType, DiffType.Unchanged);
        }
    }
}
